package com.example.lottery.service.activitystatus.impl;

import com.example.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.example.lottery.common.exception.ServiceException;
import com.example.lottery.service.ActivityService;
import com.example.lottery.service.activitystatus.ActivityStatusManager;
import com.example.lottery.service.activitystatus.operater.AbstractActivityOperator;
import com.example.lottery.service.dto.ConvertActivityStatusDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
@Slf4j
public class ActivityStatusManagerImpl implements ActivityStatusManager {
    @Autowired
    //AbstractActivityOperator 策略模式类
    private final Map<String, AbstractActivityOperator> operatorMap = new HashMap<>();
    @Autowired
    private ActivityService activityService;

    @Override
    @Transactional(rollbackFor = Exception.class)
//    保证两个 processConvertStatus 调用在同一个事务中
//    要么全部成功，要么全部回滚
//            确保数据一致性
    public void handlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //活动 状态扭转依赖奖品状态 对奖品状态有依赖性 故采用责任链模式解决  因为你要把 所有奖品抽完 活动才算结束 故有依赖关系
        //状态扭转条件可能会拓展，故采用策略模式来解决
        if(CollectionUtils.isEmpty(operatorMap)){
            log.warn("operatorMap 为空! ");
            return;
        }
        //新创建 一个currMap
        Map<String,AbstractActivityOperator> currMap=new HashMap<>(operatorMap);
        Boolean update=false;

        //先处理人员 奖品
        update=processConvertStatus(convertActivityStatusDTO,currMap,1);
        //后处理活动
        update=processConvertStatus(convertActivityStatusDTO,currMap,2)||update;
        //更新缓存
        //我只要做的目的是只要活动人员或者活动奖品更新成功 不管你活动状态是否更新成功 都更新缓存
        if(update){
            activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
        }
    }
    /**
     * 这是责任链模式的体现
     * 扭转状态
     * @param convertActivityStatusDTO
     * @param currMap
     * @param sequence
     * @return
     */
    private Boolean processConvertStatus(ConvertActivityStatusDTO convertActivityStatusDTO, Map<String, AbstractActivityOperator> currMap, int sequence) {

        Boolean update=false;
        //遍历currMap  currMap里面是操作器
        Iterator<Map.Entry<String,AbstractActivityOperator>> iterator=currMap.entrySet().iterator();
        while(iterator.hasNext()){
            AbstractActivityOperator operator=iterator.next().getValue();
            //operator是否需要转换
            if(operator.sequence()!=sequence
            || !operator.needConvert(convertActivityStatusDTO)){
                continue;
            }
            //需要转换 那就转换
            if(!operator.convert(convertActivityStatusDTO)){
                log.info("{}状态转换失败! ",operator.getClass().getName());
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_STATUS_CONVERT_ERROR);
            }
            // currMap 删除当前 Operator
            // 从currMap中删除当前已处理的操作器
            iterator.remove();
            update = true;
        }
        return update;
    }
    @Override
    public void rollbackHandlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //operatorMap 活动操作器 活动人员操作器 活动奖品操作器
        //活动需要回滚吗？？ 绝对需要回滚
        //原因：因为奖品都恢复成了INIT 则这个活动下的奖品绝对没有抽完
        for(AbstractActivityOperator operator:operatorMap.values()){
            operator.convert(convertActivityStatusDTO);
        }

        //缓存更新
        activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
    }

}
